Imports System.Collections.Generic
Imports System.Xml
Imports System.Xml.Linq
Imports System.Net
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.Text.RegularExpressions

Friend Class SharePointHelpers
    Private ReadOnly _spConnector As SharePointConnector
    Private ReadOnly _fieldHelper As SharePointFieldHelpers

    Public Sub New(ByVal spConnector As SharePointConnector)
        _spConnector = spConnector
        _fieldHelper = New SharePointFieldHelpers()
    End Sub

    Friend Function GetSpSite(ByVal url As Uri) As SharePointContainer

        Try

            Dim siteNode As XmlNode = _spConnector.GetWebsService(url).GetWeb(".").ToXmlElement

            If siteNode Is Nothing Then
                Throw New Exception("Cannot connect")
            End If

            Return New SharePointContainer(False, siteNode.Attributes("Url").Value, siteNode.Attributes("Title").Value, New Uri(siteNode.Attributes("Url").Value), SharePointContainer.TypeEnum.Site)

        Catch e As Exception
            Throw
        End Try
    End Function

    Public Function GetSiteList(ByVal url As Uri) As List(Of SharePointContainer)


        Dim sites As XmlElement = Nothing
        Try
            sites = _spConnector.GetWebsService(url).GetWebCollection().ToXmlElement
        Catch
            Return Nothing
        End Try

        Dim list As List(Of SharePointContainer) = New List(Of SharePointContainer)
        Dim item As SharePointContainer = Nothing
        For Each site As XmlNode In sites.ChildNodes
            item = New SharePointContainer(False, site.Attributes("Url").Value, site.Attributes("Title").Value, New Uri(site.Attributes("Url").Value), SharePointContainer.TypeEnum.Site)
            list.Add(item)
        Next

        Return list
    End Function

    Public Function GetLibraryList(ByVal url As Uri) As List(Of SharePointLibrary)
        Dim listNode As XmlElement
        Try
            listNode = _spConnector.GetListsService(url).GetListCollection().ToXmlElement
        Catch
            Return Nothing
        End Try

        Return (From i In listNode.ChildNodes _
            Select GetLibraryFromNode(url, DirectCast(i, XmlNode))).ToList()
    End Function

    Friend Function GetLibrary(ByVal url As Uri) As SharePointLibrary
        Try
            Dim listNode As XmlNode

            listNode = _spConnector.GetListsService(url.Parent).GetList(url.LastSegment()).ToXmlElement

            Return GetLibraryFromNode(url.Parent, listNode)

        Catch e As Exception
            Throw
        End Try
    End Function

    Private Function GetLibraryFromNode(ByVal siteUrl As Uri, ByVal listnode As XmlNode) As SharePointLibrary

        Dim libraryId = listnode.Attributes("ID").Value
        Dim spLib = New SharePointLibrary(True, libraryId, listnode.Attributes("Title").Value, siteUrl.Append(libraryId), SharePointContainer.TypeEnum.Library)

        Dim value As Integer
        If Integer.TryParse(listnode.Attributes("BaseType").Value, value) Then
            If [Enum].IsDefined(GetType(Microsoft.SharePoint.Client.BaseType), value) Then
                Select Case CType(value, Microsoft.SharePoint.Client.BaseType)
                    Case Microsoft.SharePoint.Client.BaseType.GenericList
                        spLib.BaseType = SharePointLibrary.LibraryBaseType.GenericList
                    Case Microsoft.SharePoint.Client.BaseType.DocumentLibrary
                        spLib.BaseType = SharePointLibrary.LibraryBaseType.DocumentLibrary
                    Case Microsoft.SharePoint.Client.BaseType.DiscussionBoard
                        spLib.BaseType = SharePointLibrary.LibraryBaseType.DiscussionBoard
                    Case Microsoft.SharePoint.Client.BaseType.Survey
                        spLib.BaseType = SharePointLibrary.LibraryBaseType.Survey
                    Case Microsoft.SharePoint.Client.BaseType.Issue
                        spLib.BaseType = SharePointLibrary.LibraryBaseType.Issue
                End Select
            End If
        End If

        spLib.Hidden = listnode.Attributes("Hidden").Value = "True"

        If listnode.ChildNodes.Count > 0 Then
            spLib.Fields.AddRange(GetFieldsFromXml(XElement.Parse(listnode.OuterXml), siteUrl))
        End If

        Return spLib
    End Function

    Private Function GetFieldsFromXml(ByVal element As XElement, ByVal site As Uri) As IEnumerable(Of SharePointField)
        Dim rootElement = If(element.Name.LocalName = "Fields", element, element.Element(SharePointConnector.SharePointNameSpace + "Fields"))
        Return From f In rootElement.Elements(SharePointConnector.SharePointNameSpace + "Field") _
            Where f.Attribute("StaticName") IsNot Nothing _
            Select _fieldHelper.XElementToField(f, site)
    End Function

    Friend Function GetFolder(ByVal siteUrl As Uri, ByVal libraryName As String, ByVal folder As String) As SharePointContainer

        Dim seperators = New Char() {"/"c, "\"c}
        folder = folder.Trim(seperators)
        Dim reg = Regex.Match(folder, "^(.*[/\\])?([^/\\]*)$")
        Dim containingFolder = reg.Groups(1).Value.Trim(seperators)
        Dim leafFolder = reg.Groups(2).Value

        Dim query = <Query>
                        <Where>
                            <And>
                                <Eq><FieldRef Name="FileLeafRef"/><Value Type="Text"><%= leafFolder %></Value></Eq>
                                <Eq><FieldRef Name="FSObjType"/><Value Type="Lookup">1</Value></Eq>
                            </And>
                        </Where>
                    </Query>

        Dim listsService = _spConnector.GetListsService(siteUrl)
        Dim listInfo = XElement.Parse(listsService.GetList(libraryName).ToXmlElement.OuterXml)
        Dim internalLibraryName = Regex.Match(listInfo.Attribute("RootFolder").Value, "[^/]+$").Value

        Dim queryOptions = <QueryOptions/>

        If Not String.IsNullOrEmpty(containingFolder) Then
            queryOptions.Add(<Folder><%= internalLibraryName + "/" + containingFolder %></Folder>)
        End If

        Try
            Dim listNode As XmlNode = listsService.GetListItems(libraryName, String.Empty, query, Nothing, Nothing, queryOptions, Nothing).ToXmlElement

            Dim ns As XNamespace = "#RowsetSchema"

            Return (From e In XElement.Parse(listNode.InnerXml).Elements(ns + "row") _
                Select New SharePointFolder(_spConnector.SiteUrl, e)).Single

        Catch e As Exception
            Throw
        End Try
    End Function

    Public Function GetFolderList(ByVal url As Uri, ByVal listName As String, ByVal libPath As String, ByVal rowLimit As String) As List(Of SharePointContainer)
        Dim options As XElement = Nothing
        If libPath IsNot Nothing Then
            options = <QueryOptions>
                          <Folder><%= libPath %></Folder>
                      </QueryOptions>
        End If

        Dim query = <Query>
                        <Where>
                            <And>
                                <IsNull><FieldRef Name='DocIcon'/></IsNull>
                                <Eq><FieldRef Name='FSObjType'/><Value Type='Lookup'>1</Value></Eq>
                            </And>
                        </Where>
                    </Query>
        Dim fields = <ViewFields>
                         <FieldRef Name='LinkFilename'/>
                         <FieldRef Name='DocIcon'/>
                         <FieldRef Name='UniqueId'/>
                         <FieldRef Name='FileLeafRef'/>
                         <FieldRef Name='FileRef'/>
                         <FieldRef Name='ID'/>
                         <FieldRef Name='HTML File Type'/>
                     </ViewFields>

        Dim listItems As XmlElement
        listItems = _spConnector.GetListsService(url).GetListItems(listName, Nothing, query, fields, rowLimit, options, String.Empty).ToXmlElement

        Dim ns As XNamespace = "#RowsetSchema"
        Dim siteurl As Uri
        If url.AbsolutePath = "/" Then
            siteurl = _spConnector.SiteUrl
        Else
            siteurl = New Uri(url.ToString().Replace(url.AbsolutePath, ""))
        End If

        Dim folders = (From e In XElement.Parse(listItems.InnerXml).Elements(ns + "row") _
                Select New SharePointFolder(siteurl, e))

        Dim folderList As List(Of SharePointContainer) = New List(Of SharePointContainer)
        For Each folder As SharePointFolder In folders
            If folder.ContainerType = SharePointContainer.TypeEnum.Folder Then
                folderList.Add(folder)
            End If
        Next

        Return folderList
    End Function

    Public Function GetDocumentList(ByVal url As Uri, ByVal listName As String, ByVal libPath As String, ByVal rowLimit As String) As List(Of SharePointContainer)
        Dim options As XElement = Nothing
        If libPath IsNot Nothing Then
            options = <QueryOptions>
                          <Folder><%= libPath %></Folder>
                      </QueryOptions>
        End If

        Dim query = <Query>
                        <Where>
                            <Neq><FieldRef Name='FSObjType'/><Value Type='Lookup'>1</Value></Neq>
                        </Where>
                    </Query>
        Dim fields = <ViewFields>
                         <FieldRef Name='LinkFilename'/>
                         <FieldRef Name='DocIcon'/>
                         <FieldRef Name='UniqueId'/>
                         <FieldRef Name='FileLeafRef'/>
                         <FieldRef Name='FileRef'/>
                         <FieldRef Name='ID'/>
                         <FieldRef Name='HTML File Type'/>
                     </ViewFields>

        Dim listItems As XmlElement
        Dim temp As XElement
        temp = _spConnector.GetListsService(url).GetListItems(listName, Nothing, query, fields, rowLimit, options, String.Empty)
        listItems = temp.ToXmlElement

        Dim ns As XNamespace = "#RowsetSchema"
        Dim siteurl As Uri
        If url.AbsolutePath = "/" Then
            siteurl = _spConnector.SiteUrl
        Else
            siteurl = New Uri(url.ToString().Replace(url.AbsolutePath, ""))
        End If

        Dim folders = (From e In XElement.Parse(listItems.InnerXml).Elements(ns + "row") _
                Select New SharePointFolder(siteurl, e))

        Dim folderList As List(Of SharePointContainer) = New List(Of SharePointContainer)
        For Each folder As SharePointFolder In folders
            If folder.ContainerType = SharePointContainer.TypeEnum.Folder Then
                folderList.Add(folder)
            End If
        Next

        Return folderList
    End Function

End Class
